
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>事件总线 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>事件总线 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">Guava EventBus 实现了哪种设计模式？其核心包含哪三个角色？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">EventBus 核心是发布-订阅模式（Publish-Subscribe Pattern）。它主要包含三个角色：1. 事件（Event）：包含需要传递的信息；2. 发布者（Publisher）：发布事件到 EventBus；3. 订阅者（Subscriber）：注册到 EventBus 并处理感兴趣的事件。</div>
          </div>
          <div class="card-source">来源: 1.2 EventBus的核心概念</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">EventBus 是如何存储和管理所有订阅者信息的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">EventBus 通过一个名为 SubscriberRegistry（订阅者注册表）的核心组件来管理订阅者。该组件内部使用一个线程安全的 ConcurrentMap 来缓存每个事件类型（Class<?>）对应的订阅者列表（CopyOnWriteArraySet<Subscriber>）。</div>
          </div>
          <div class="card-source">来源: 1.4 订阅者注册表的实现</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">EventBus 如何识别一个普通类中的方法为事件处理方法？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">EventBus 使用 Java 反射机制来扫描注册对象的所有方法。如果一个方法被 `@Subscribe` 注解标记，并且有且仅有一个参数（该参数类型即为它订阅的事件类型），那么这个方法就会被识别并注册为事件处理器。</div>
          </div>
          <div class="card-source">来源: 3.1 @Subscribe注解的设计与实现</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">Guava EventBus 提供了哪两种线程模型？它们分别适用于什么场景？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">EventBus 提供了两种线程模型：1. 同步EventBus：事件在发布线程中同步处理，适用于处理简单快速、需要立即响应且保证顺序的场景。2. 异步AsyncEventBus：事件在独立的线程池中异步处理，适用于耗时处理、提高并发性、发布者无需等待的场景。</div>
          </div>
          <div class="card-source">来源: 2.2 线程模型分析</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">在 EventBus 中，Dispatcher 组件的作用是什么？它有哪些主要实现？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Dispatcher 组件负责处理事件分发的具体逻辑，即如何将事件传递给订阅者。文档中提到了两种主要实现：1. ImmediateDispatcher：在调用 post() 的线程中同步分发事件。2. AsyncDispatcher：使用线程池异步分发事件。</div>
          </div>
          <div class="card-source">来源: 2.1 事件分发器Dispatcher的设计</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">当一个事件被发布后，如果没有对应的订阅者来处理它，EventBus 会如何处理这种情况？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">当发布一个没有订阅者的事件时，EventBus 会将这个未被消费的事件包装成一个 DeadEvent 类的实例，并重新发布。开发者可以创建一个订阅 DeadEvent 的处理器来捕获并记录这些“死亡”事件。</div>
          </div>
          <div class="card-source">来源: 2.3 死锁问题和处理机制</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">EventBus 是如何实现调用订阅者中的私有（private）方法的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">在创建 Subscriber 对象时，EventBus 会获取到处理方法的 Method 引用，并调用 `method.setAccessible(true)`。这个操作会取消 Java 的访问权限检查，从而允许 EventBus 通过反射调用订阅者对象中的非公共方法，包括私有方法。</div>
          </div>
          <div class="card-source">来源: 3.2 Subscriber对象的设计</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">如果订阅者在处理事件时抛出异常，EventBus 提供了什么机制来处理这些异常？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">EventBus 提供了 SubscriberExceptionHandler 接口来处理订阅者抛出的异常。开发者可以创建该接口的自定义实现，并在构造 EventBus 时传入，从而定义自己的异常处理逻辑，例如记录到监控系统或发送警报。</div>
          </div>
          <div class="card-source">来源: 5.2 错误处理策略</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">根据文档中的电商案例，使用 EventBus 构建事件驱动系统有哪些关键优势？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">关键优势包括：1. 解耦：事件发布者（如订单服务）不需要知道处理事件的具体组件。2. 可扩展：添加新的事件处理器（如积分服务）无需修改现有代码。3. 可测试：每个组件都可以被独立测试。4. 灵活：可以根据业务需求动态注册或注销处理器。</div>
          </div>
          <div class="card-source">来源: 4. 构建高效的事件驱动系统</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
